#include <gtest/gtest.h>
#include "scripting/script_interpreter.h"
#include "../sample/battery_level_check.h"
#include "../sample/docking_task.h"
#include "../sample/navigation_task.h"
#include "../sample/screen_return_zero_check.h"
#include "../sample/screen_return_zero_task.h"
#include "../sample/switch_high_current.h"
#include "../sample/resume_task.h"
#include "task/task_chain.h"
#include "task/task_controller.h"
#include "types/reflex.h"
#include "test_print_info.h"
#include <thread>

using namespace script;

namespace
{
void printErrorInfo(const ErrorInfo &error_info)
{
    printf("errors:\t%s\n%d:%d, %s\n\n", error_info.line_code.c_str(), error_info.line, error_info.column, error_info.error_message.c_str());
}
}

class TestReactiveScriptRun: public testing::Test
{
protected:
private:
protected:
    void SetUp() override
    {
        REGISTER_TASK_TYPE(BatteryLevelCheck)
        REGISTER_TASK_TYPE(DockingTask)
        REGISTER_TASK_TYPE(NavigationTask)
        REGISTER_TASK_TYPE(ScreenReturnZeroCheck)
        REGISTER_TASK_TYPE(ScreenReturnZeroTask)
        REGISTER_TASK_TYPE(SwitchHighCurrent)
        REGISTER_TASK_TYPE(ResumeTask)
    }
    void TearDown() override
    {
        UNREGISTER_TASK_TYPE(BatteryLevelCheck)
        UNREGISTER_TASK_TYPE(DockingTask)
        UNREGISTER_TASK_TYPE(NavigationTask)
        UNREGISTER_TASK_TYPE(ScreenReturnZeroCheck)
        UNREGISTER_TASK_TYPE(ScreenReturnZeroTask)
        UNREGISTER_TASK_TYPE(SwitchHighCurrent)
        UNREGISTER_TASK_TYPE(ResumeTask)
    }
};

TEST_F(TestReactiveScriptRun, test_run_reactive_simple)
{
    const char *code = R"(
        var navigation_task = NavigationTask("navigation_task")
        var battery_level_check = BatteryLevelCheck("battery_level_check")
        var screen_return_zero_check = ScreenReturnZeroCheck("screen_return_zero_check")
        var docking_task = DockingTask("docking_task")

        #reactive测试
        reactive(battery_level_check)
        {
            navigation_task
        }
    )";
    task::TaskController task_controller;
    task_controller.setMaxParallelTaskCount(2);
    ScriptInterpreter script_run;
    if (auto scheduler = script_run.interpret(code))
    {
        printf("%s\n", scheduler.value()->toString().c_str());
        scheduler.value()->run();
        SUCCEED();
    }
    else
    {
        printErrorInfo(script_run.getErrorInfo());
        FAIL();
    }
}

TEST_F(TestReactiveScriptRun, test_run_reactive_simple_pause)
{
    const char *code = R"(
        var navigation_task = NavigationTask("navigation_task")
        var battery_level_check = BatteryLevelCheck("battery_level_check")
        var screen_return_zero_check = ScreenReturnZeroCheck("screen_return_zero_check")
        var docking_task = DockingTask("docking_task")
        var resume_task = ResumeTask("resume_task")

        #reactive测试
        resume_task
        reactive(battery_level_check)
        {
            navigation_task
        }
    )";
    task::TaskController task_controller;
    task_controller.setMaxParallelTaskCount(2);
    ScriptInterpreter script_run;
    if (auto scheduler = script_run.interpret(code))
    {
        printf("%s\n", scheduler.value()->toString().c_str());

//        auto task_chain = new task::TaskChain("123", scheduler.value());
//        task_controller.startTaskChain(task_chain);
//        while (true)
//        {}
        SUCCEED();
    }
    else
    {
        printErrorInfo(script_run.getErrorInfo());
        FAIL();
    }
}
TEST_F(TestReactiveScriptRun, test_run_reactive_simple_pause_resume)
{
    const char *code = R"(
        var navigation_task = NavigationTask("navigation_task")
        var battery_level_check = BatteryLevelCheck("battery_level_check")
        var screen_return_zero_check = ScreenReturnZeroCheck("screen_return_zero_check")
        var docking_task = DockingTask("docking_task")

        #reactive测试
        reactive(battery_level_check)
        {
            navigation_task
        }
    )";
    task::TaskController task_controller;
    task_controller.setMaxParallelTaskCount(2);
    ScriptInterpreter script_run;
    if (auto scheduler = script_run.interpret(code))
    {
        printf("%s\n", scheduler.value()->toString().c_str());

        auto task_chain = new task::TaskChain("123", scheduler.value());
        task_controller.startTaskChain(task_chain);
        std::thread([&task_controller]
                    {
                        sleep(5);
                        task_controller.resumeTaskChain("123");
                    }).detach();
        while (true)
        {}
        SUCCEED();
    }
    else
    {
        printErrorInfo(script_run.getErrorInfo());
        FAIL();
    }
}

